package com.ljf.common.core;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.ljf.authority.enums.AuthorityBaseApiTabulationMethodEnum;
import com.ljf.authority.service.IAuthorityBaseApiTabulationService;
import com.ljf.common.exception.ServiceException;
import com.ljf.common.exception.SystemException;
import com.ljf.common.utils.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 全局控制器AOP处理
 *
 * @author LJF
 * @since 2024-10-25
 */
@Aspect
@Component
public class ControllerAopHandler {

    @Resource
    private ApplicationContext applicationContext;
    
    @Value("${spring.datasource.dynamic.primary}")
    private String dynamicPrimary = null;

    private IAuthorityBaseApiTabulationService authorityBaseApiTabulationService;
    private Map<String, Integer> methodMap;

    /**
     * 所有方法切点
     */
    @Pointcut("execution(* com.ljf.*.web.*.*(..))")
    public void allApi() {

    }

    /**
     * 处理访问接口
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("allApi()")
    public Object aroundMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = this.getRequest();
        boolean synchronization = checkAuthority(request.getRequestURI(), getMethodCode(request.getMethod()));
        Object proceed = joinPoint.proceed();
        if (synchronization) {
            DynamicDataSourceContextHolder.push(StringUtil.equals(dynamicPrimary, "master") ? "slave" : "master");
            joinPoint.proceed();
            DynamicDataSourceContextHolder.clear();
        }
        return proceed;
    }

    /**
     * 获取请求方法编码
     *
     * @param method
     * @return
     * @throws SystemException
     */
    private Integer getMethodCode(String method) throws SystemException {
        Map<String, Integer> map = getMethodMap();
        if (!map.containsKey(method)) {
            throw new SystemException("请求方式异常");
        }
        return map.get(method);
    }

    /**
     * 获取请求方法到编码的映射
     *
     * @return
     */
    private Map<String, Integer> getMethodMap() {
        if (methodMap == null) {
            methodMap = Arrays.stream(AuthorityBaseApiTabulationMethodEnum.values())
                    .collect(
                            Collectors.toMap(
                                    AuthorityBaseApiTabulationMethodEnum::getName,
                                    AuthorityBaseApiTabulationMethodEnum::getCode,
                                    (a, b) -> a)
                    );
        }
        return methodMap;
    }

    /**
     * 获取请求
     *
     * @return
     * @throws SystemException
     */
    private HttpServletRequest getRequest() throws SystemException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            throw new SystemException("获取请求失败");
        }
        return attributes.getRequest();
    }

    /**
     * 权限校验
     *
     * @param url
     * @param method
     * @return
     * @throws ServiceException
     */
    private boolean checkAuthority(String url, Integer method) throws ServiceException {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        return getAuthorityBaseApiTabulationService().checkAuthorityApi(request.getHeader("user"), url, method);
    }

    /**
     * 获取API列表定义Bean
     *
     * @return
     */
    private IAuthorityBaseApiTabulationService getAuthorityBaseApiTabulationService() {
        if (authorityBaseApiTabulationService == null) {
            authorityBaseApiTabulationService = applicationContext.getBean(IAuthorityBaseApiTabulationService.class);
        }
        return authorityBaseApiTabulationService;
    }

}
